<?php

namespace app\api\controller;

use app\common\controller\Api;
use fast\Arr;
use fast\Http;
use think\Db;
use think\Config;
use app\common\model\order\Order;
use think\Log;

/**
 * 首页接口
 */
class Kj extends Api
{
    protected $noNeedLogin = ['notify_agencypay','notify_pay'];
    private array  $params = [];

    private string $apiUrl = 'https://api.taijinnet.com';
    private string $channelCode = "tmkj1";

    private string $mechId = "10001119";
    private string $appId = "2000001117";
    private string $md5Key = "HV3Aex2lnVn0eFGJHlXRHOKKsnb4mAvA";


    private array $store;
    public function _initialize()
    {
        parent::_initialize();
        //不需要验签的
        $actionname = strtolower($this->request->action());
        //验证参数

        $this->params = $this->request->post();
        Log::info("回调通知:".json_encode($this->params,JSON_UNESCAPED_UNICODE));
        if (!in_array($actionname,$this->noNeedLogin)){
            if (!(isset($this->params['sign'])
                && isset($this->params['mechId'])
                && isset($this->params['appId'])
                && isset($this->params['version'])
                && isset($this->params['signMethod'])
            )){
                $this->error("参数错误");
            }

            $map = [
                'mechId' => $this->params['mechId'],
                'appId' => $this->params['appId'],
                'status' => 'normal',
            ];
            //验证appid 等
            $store = DB::name("admin")->field("id,mechId,appId,md5,status,money,fee,withdraw")->where($map)->find();

            if (!$store){
                $this->error("商户不存在");
            }
            $this->store   = $store;
            //验签
            if (!$this->storeYanqian($store)){
                $this->error("验签失败");
            }
        }

    }

    /**
     * 请求交易（发送短信验证码）
     *
     */
    public function paySms()
    {
        $params = $this->params;
        $method = "/gateway/kj/paySms";

        //写入数据录计算收益
        $res = $this->execute($method,$params);

        if ($res['respCode'] == "TC0000"){
            $params['respCode'] = Arr::get($res,'respCode','');
            $params['respMsg'] = Arr::get($res,'respMsg','');
            $params['tradeNo'] = Arr::get($res,'tradeNo','');
            $params['outTradeNo'] = Arr::get($res,'outTradeNo','');
            $params['txnStatus'] = Arr::get($res,'txnStatus','');
            $params['smsNo'] = Arr::get($res,'smsNo','');
            $params['tradeType'] = 1;
            $params['appId'] = $this->store['appId'];
            $params['mechId'] = $this->store['mechId'];
            $params['store_id'] = $this->store['id'];
            if($params['txnStatus']){
                $params['status'] = match ($res['txnStatus']) {
                    'N','UP','IP','SP'      => 0,
                    'S'                     => 1,
                    'CF','F','C'            => -1,
                    default                 => 0
                };
            }

            $Order = new Order($params);
            $res2 = $Order->allowField(true)->save();
            if (!$res2){
                return json(['msg'=>"订单写入失败"],500);
            }
        }
        return json($res);
    }

    /**
     * 确认交易
     *
     */
    public function payConfirm()
    {

        $params = $this->params;
        $method = '/gateway/kj/payConfirm';
        $res = $this->execute($method,$params);
        if ($res['respCode'] == "TC0000"){
            $tradeNo = Arr::get($res,'tradeNo','');
            $outTradeNo = Arr::get($res,'outTradeNo','');
            $params['respCode'] = Arr::get($res,'respCode','');
            $params['respMsg'] = Arr::get($res,'respMsg','');
            $params['txnAmount'] = Arr::get($res,'txnAmount','');
            $params['charge'] = Arr::get($res,'charge','');
            $params['txnStatus'] = Arr::get($res,'txnStatus','');
            $params['smsCode'] = Arr::get($res,'smsCode','');
            if($params['txnStatus']){
                $params['status'] = match ($res['txnStatus']) {
                    'N','UP','IP','SP'      => 0,
                    'S'                     => 1,
                    'CF','F','C'            => -1,
                    default                 => 0
                };
            }
            $params['shouyi'] = floor(bcsub($params['charge'],bcdiv(bcmul($params['txnAmount'],$this->store['fee']),
                10000,2),2));
            $Order = new Order();
            $res2 = $Order->allowField(true)->save($params,['tradeNo' => $tradeNo,'outTradeNo' => $outTradeNo,'tradeType'=>1]);
        }
        return json($res);
    }

    /**
     * 代付交易（付款到银行卡）
     *
     */
    public function agencyPay()
    {
        $params = $this->params;
        $method = "/gateway/kj/agencyPay";
        $res = $this->execute($method,$params);
        if ($res['respCode'] == "TC0000"){
            $params['tradeNo'] = Arr::get($res,'tradeNo','');
            $params['outTradeNo'] = Arr::get($res,'outTradeNo','');
            $params['txnAmount'] = Arr::get($res,'txnAmount','');
            $params['charge'] = Arr::get($res,'charge','');
            $params['txnStatus'] = Arr::get($res,'txnStatus','');
            $params['description'] = Arr::get($res,'description','');
            if($params['txnStatus']){
                $params['status'] = match ($res['txnStatus']) {
                    'N','UP','IP','SP'      => 0,
                    'S'                     => 1,
                    'CF','F','C'            => -1,
                    default                 => 0
                };
            }

            $params['shouyi'] = bcsub($params['charge'],$this->store['withdraw']);
            $params['tradeType'] = 2;
            $params['appId'] = $this->store['appId'];
            $params['mechId'] = $this->store['mechId'];
            $params['store_id'] = $this->store['id'];

            $Order = new Order($params);
            $res2 = $Order->allowField(true)->save();
            if (!$res2){
                Log::info("订单写入失败:".json_encode($params,JSON_UNESCAPED_UNICODE));
            }
        }
        return json($res);
    }

    /**
     * 查询扣款交易
     *
     */
    public function queryOrder()
    {
        $params = $this->params;
        $method = "/gateway/kj/queryOrder";
        $res = $this->execute($method,$params);

        return json($res);
    }



    /**
     * 代付查询（付款到银行卡）
     *
     */
    public function queryAgencyPay()
    {
        $params = $this->request->post();
        $method = "/gateway/kj/queryAgencyPay";
        $res = $this->execute($method,$params);
        return json($res);
    }

    /**
     * 付款通知
     *
     */
    public function notify_pay()
    {
        $res = $this->request->post();
        $update = [];
        Log::info("付款回调通知:".json_encode($res,JSON_UNESCAPED_UNICODE));
        $tradeNo = Arr::get($res,'tradeNo','');
        $outTradeNo = Arr::get($res,'outTradeNo','');
        if ($tradeNo && $outTradeNo){
            $update['txnAmount'] = Arr::get($res,'txnAmount','');
            $update['charge'] = Arr::get($res,'charge','');
            $update['txnStatus'] = Arr::get($res,'txnStatus','');
            $update['description'] = Arr::get($res,'description','');
            if($update['txnStatus']){
                $update['status'] = match ($res['txnStatus']) {
                    'N','UP','IP','SP'      => 0,
                    'S'                     => 1,
                    'CF','F','C'            => -1,
                    default                 => 0
                };
            }


            $Order = new Order();
            $Order->allowField(true)->save($update,['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,
                'tradeType'=>1]);

            $Order = Db::name("order")->where(['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,'tradeType'=>1])->find();
            //更新失败写入日志
            if ($Order){
                $notifyUrl = $Order['notifyUrl'];

                $res['mechId'] = $Order['mechId'];
                $res['appId'] = $Order['appId'];
                unset($res['sign']);
                return Http::post($notifyUrl,$res);

            }else{
                Log::info("付款通知更新失败:".json_encode(['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,'tradeType'=>1],JSON_UNESCAPED_UNICODE));
            }
        }
    }

    /**
     * 代付通知
     *
     */
    public function notify_agencypay()
    {

        $res = $this->request->post();
        Log::info("代付回调通知:".json_encode($res,JSON_UNESCAPED_UNICODE));

        $update = [];
        $tradeNo = Arr::get($res,'tradeNo','');
        $outTradeNo = Arr::get($res,'outTradeNo','');
        if ($tradeNo && $outTradeNo){
            $update['txnAmount'] = Arr::get($res,'txnAmount','');
            $update['charge'] = Arr::get($res,'charge','');
            $update['txnStatus'] = Arr::get($res,'txnStatus','');
            $update['description'] = Arr::get($res,'description','');
            if($update['txnStatus']){
                $update['status'] = match ($res['txnStatus']) {
                    'N','UP','IP','SP'      => 0,
                    'S'                     => 1,
                    'CF','F','C'            => -1,
                    default                 => 0
                };
            }
            $Order = new Order();
            $Order->allowField(true)->save($update,['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,
                'tradeType'=>2]);

            $Order = Db::name("order")->where(['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,'tradeType'=>2])->find();

            if ($Order){
                $notifyUrl = $Order['notifyUrl'];
                $res['mechId'] = $Order['mechId'];
                $res['appId'] = $Order['appId'];
                unset($res['sign']);
                return Http::post($notifyUrl,$res);
            }else{
                 Log::info("代付通知更新失败:".json_encode(['tradeNo'=>$tradeNo,'outTradeNo'=>$outTradeNo,'tradeType'=>2],JSON_UNESCAPED_UNICODE));
            }
        }
    }
    /**
     * 请求
     */
    private function execute($method,$params)
    {

        Log::info("请求前数据:".json_encode($params,JSON_UNESCAPED_UNICODE));

        if ($method == '/gateway/kj/paySms'){
            $params['notifyUrl'] = url("kj/notify_pay",'',true,true);
        }
        if ($method == '/gateway/kj/agencyPay'){
            $params['notifyUrl'] = url("kj/notify_agencypay",'',true,true);
        }

        $public = [
            'mechId' => $this->mechId,
            'appId' => $this->appId,
            'timestamp' => date("Y-m-d H:i:s"),
            'nonceStr' => md5(uniqid()),
            'version' => '1.0',
            'signMethod' => 'md5',
        ];
        $params = array_merge($params,$public);
        $params["sign"] = $this->createSign($params,$this->md5Key);
        $url = $this->apiUrl.$method;
        $header = [
            CURLOPT_HTTPHEADER=>["content-type: application/json","charset=UTF-8"]
        ];
        Log::info("处理后数据:".json_encode($params,JSON_UNESCAPED_UNICODE));
        $res = Http::post($url,json_encode($params),$header);

        Log::info("请求后数据:".json_encode($res,JSON_UNESCAPED_UNICODE));

        $res = json_decode($res,true);
        $actionname = strtolower($this->request->action());
        if (!in_array($actionname,$this->noNeedLogin)){
            $res['appId'] = $this->store['appId'];
            $res['mechId'] = $this->store['mechId'];
        }

        if (isset($res['sign'])){
            unset($res['sign']);
        }
        return $res;
    }

    /**
     * 验证商户签名
     */
    private function storeYanqian($store)
    {
        $params = $this->params;
        $init_sign = $params['sign'];
        unset($params['sign']);
        $params['mechId'] = $store['mechId'];
        $params['appId'] = $store['appId'];
        $params['version'] = '1.0';
        $params['signMethod'] = 'md5';
        $sign= $this->createSign($params,$store['md5']);
        //var_dump($sign);
        if ($init_sign == $sign){
            return true;
        }else{
            Log::info("验证商户签名失败:".$sign);
            return false;
        }
    }

    private function createSign($params, $md5Key) {
        // 过滤空参数
        $params = array_filter($params, function($value) {
            return !is_null($value) && $value !== '';
        });
        ksort($params); // 按参数名升序排序
        $stringToSign = '';
        foreach ($params as $key => $value) {
            if ($key != 'sign' && $value != '') {
                $stringToSign .= $key . '=' . $value . '&';
            }
        }
        $stringToSign = trim($stringToSign,'&').$md5Key;
        return md5($stringToSign);
    }

}
